package com.appshelves.model.saveable;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import com.appshelves.utils.Utils;

@SuppressWarnings("serial")
public class SaveableList<T extends Saveable> extends ArrayList<T> {

    protected Class<T> cls;

    public SaveableList(Class<T> clazz) {
        super();
        this.cls = clazz;
    }

    public boolean load() {
        return Utils.readFromFile(getFileName(), new Utils.ReadOperation() {

            @Override
            public void run(DataInputStream stream) throws IOException {
                performLoad(stream, null);
            }

            @Override
            public void onFail() {

            }
        });
    }

    public boolean load(DataInputStream stream) {
        return load(stream, null);
    }

    public boolean load(DataInputStream stream, final Object arg) {

        return Utils.readFromStream(stream, new Utils.ReadOperation() {

            @Override
            public void run(DataInputStream stream) throws IOException {
                performLoad(stream, arg);
            }

            @Override
            public void onFail() {
            }
        });
    }

    ///

    public void save() {
        Utils.writeToFile(getFileName(), new Utils.WriteOperation() {

            @Override
            public void run(DataOutputStream stream) throws IOException {
                performSave(stream);
            }

            @Override
            public void onFail() {
            }
        });
    }

    public void saveToStream(DataOutputStream stream) {
        Utils.writeToStream(stream, new Utils.WriteOperation() {

            @Override
            public void run(DataOutputStream stream) throws IOException {
                performSave(stream);
            }

            @Override
            public void onFail() {
            }
        });
    }

    public static void eraseDataFile(Class<?> cls) {
        Utils.eraseDataFile(generateFileName(cls));
    }

    /// implementation

    protected String getFileName() {
        return generateFileName(cls);
    }

    protected static String generateFileName(Class<?> cls) {
        return cls.getSimpleName();
    }

    private void performLoad(DataInputStream stream, Object arg) throws IOException {
        int size = stream.readInt();
        ensureCapacity(size);
        for (int i = 0; i < size; i++) {
            T el = createElement(stream, arg);
            if (el == null)
                throw new IOException();
            add(el);
        }
        log("loaded " + size());
    }

    protected T createElement(DataInputStream stream, Object arg) throws IOException {
        return T.createFromStream(stream, cls, arg);
    }

    private void performSave(DataOutputStream stream) throws IOException {
        stream.writeInt(size());
        for (T el : this)
            el.writeToStream(stream);
        log("saved " + size());
    }

    /// debug

    private void log(String msg) {
        Utils.log(cls.getSimpleName() + " list", msg);
    }

    public void log() {
        log(logCaption());
        for (T el : this)
            el.log();
    }

    protected String logCaption() {
        return "size: " + size();
    }

}
